﻿using CPPEI.Coolzon.Common;
using CPPEI.Coolzon.Service.Contract;
using CPPEI.Coolzon.ServiceProxy;
using CPPEI.Coolzon.ServiceProxy.MainServiceRef;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace CPPEI.Coolzon.UI.Views
{
    public enum HeartbeatThreadWorkMode
    {
        /// <summary>
        /// 仅保持连接
        /// </summary>
        KeepAlive = 0x01,
        /// <summary>
        /// 保持连接并上传状态
        /// </summary>
        UploadViewState = 0x02
    }
    /// <summary>
    /// 心跳线程,不断的向服务器发送本地的视图状态，
    /// 如果发现了终端状态不正确，那么修改终端的状态为断开连接。
    /// 如果发现了现在使用的主服务器在本次的出错列表里，则启动切换主服务器的线程。
    /// </summary>
    public static class HeartbeatThread
    {
        private static Thread s_thread;

        private static bool s_isRunning = false;
        private static EventWaitHandle s_waitHandle;
        private static long s_latestTicks = 0;
        private static object s_lockObj = new object();

        private static HeartbeatThreadWorkMode s_workMode = HeartbeatThreadWorkMode.KeepAlive;

        /// <summary>
        /// 以keepalive模式启动
        /// </summary>
        public static void Start()
        {
            Start(HeartbeatThreadWorkMode.KeepAlive);
        }

        public static void Start(HeartbeatThreadWorkMode mode)
        {
            lock (s_lockObj)
            {
                if (s_thread == null && s_isRunning == false)
                {
                    s_workMode = mode;
                    s_waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset);

                    s_thread = new Thread(Running);
                    s_thread.Name = "HeartbeatThread";
                    Logger.DebugToTag(Library.LogTag, "心跳线程启动");
                    s_isRunning = true;
                    s_thread.Start();
                }
            }
        }

        public static void SetMode(HeartbeatThreadWorkMode mode)
        {
            s_workMode = mode;
        }

        public static void Stop()
        {
            lock (s_lockObj)
            {
                if (s_thread != null && s_isRunning)
                {
                    s_isRunning = false;
                    s_waitHandle.WaitOne();
                    Logger.DebugToTag(Library.LogTag, "心跳线程停止");
                }
            }
        }

        private static void Running()
        {
            Logger.DebugToTag(Library.LogTag, "心跳线程运行开始");
            while (s_isRunning)
            {
                // 心跳线程没有终止，并且终端处于受控状态
                if (DateTime.Now.Ticks - s_latestTicks > TimeSpan.FromSeconds(2).Ticks)
                {
                    // 发送本地状态到服务器
                    List<MainServiceProxy> errorProxyList = null;
                    DoRunning(ref errorProxyList);

                    #region 检测是否需要启动主服务器切换线程
                    //是否需要切换主服务
                    bool needSwitchMainServer = false;
                    if (UIContext.Current.IsDomainOperator())
                    {
                        //如果当前终端是操作员
                        if (UIContext.Current.MainServer4Switching != null)
                        {
                            #region
                            //目前正在切换主服务器中，如果正在切换的服务器出错了，那么需要重新切换主服务器
                            for (int index = 0; index < ClientProxyManager.Instance.Proxies.Count; index++)
                            {
                                MainServiceProxy proxy = ClientProxyManager.Instance.Proxies[index];
                                if (string.Equals(proxy.IP, UIContext.Current.MainServer4Switching.IP)
                                    && proxy.Port == UIContext.Current.MainServer4Switching.Port
                                    && proxy.State == ServiceProxyState.Disconnected)
                                {
                                    needSwitchMainServer = true;
                                    break;
                                }
                            }
                            #endregion
                        }
                        else if (errorProxyList != null)
                        {
                            #region 
                            //如果出错的网络连接代理中包含目前的主服务器代理，那么需要发送切换主服务的指令。
                            for (int index = 0; index < errorProxyList.Count; index++)
                            {
                                MainServiceProxy proxy = errorProxyList[index];
                                if (proxy.IP == UIContext.Current.MainServerIP
                                    && proxy.Port == UIContext.Current.MainServerPort)
                                {
                                    needSwitchMainServer = true;
                                    break;
                                }
                            }

                            #endregion
                        }
                    }
                    if (needSwitchMainServer)
                    {
                        UIContext.Current.UpdateMainServer4Switching(null);
                        // 如果主服务器在出错的服务器列表中，发送切换主服务指令
                        // 清空掉本地存储的主服务器地址和端口
                        UIContext.Current.UpdateMainServer(string.Empty, 0);
                        // 启动切换主服务的线程
                        SwitchMainServerThread.Start();
                    }
                    #endregion

                    s_latestTicks = DateTime.Now.Ticks;
                }
                Thread.Sleep(100);
            }

            s_waitHandle.Set();
            s_waitHandle = null;
            s_thread = null;


            Logger.DebugToTag(Library.LogTag, "心跳线程运行结束");
        }

        /// <summary>
        /// 上传本地视图状态到服务器
        /// </summary>
        /// <param name="errorProxyList">出错的主服务代理列表</param>
        private static void DoRunning(ref List<MainServiceProxy> errorProxyList)
        {
            List<Coolzon.Event.UI.UINetConnectionStateFeedbackEvent.NetConnectionState> netStateList = new List<Coolzon.Event.UI.UINetConnectionStateFeedbackEvent.NetConnectionState>();

            for (int index = 0; index < ClientProxyManager.Instance.Proxies.Count; index++)
            {
                MainServiceProxy proxy = ClientProxyManager.Instance.Proxies[index];
                if (s_workMode == HeartbeatThreadWorkMode.UploadViewState)
                {
                    UploadViewState(ref errorProxyList, netStateList, proxy);
                }
                else
                {
                    KeepAlive(ref errorProxyList, netStateList, proxy);
                }
            }

            Coolzon.Event.UI.UIEventBus.PublishAsync(new Coolzon.Event.UI.UINetConnectionStateFeedbackEvent(netStateList));
        }

        private static void UploadViewState(ref List<MainServiceProxy> errorProxyList,
            List<Coolzon.Event.UI.UINetConnectionStateFeedbackEvent.NetConnectionState> netStateList,
            MainServiceProxy proxy)
        {
            if (proxy.State != ServiceProxyState.Connected)
            {
                if (proxy.State == ServiceProxyState.ReconnectFinished)
                {
                    Common.Logger.WarningToTag(Library.LogTag, "服务代理{0}:{1}的state:{2},修改为Connected,本次不发送心跳信号",
                        proxy.IP,
                        proxy.Port,
                        proxy.State);
                    proxy.State = ServiceProxyState.Connected;
                }

                netStateList.Add(new Coolzon.Event.UI.UINetConnectionStateFeedbackEvent.NetConnectionState(proxy.IP,
                    proxy.Port, false));
                return;
            }

            try
            {
                ReqUploadViewStateData requestData = new ReqUploadViewStateData();
                RenderView renderView = UI.UIContext.Current.RenderView as RenderView;
                if (renderView != null)
                {
                    Coolzon.ViewState.ViewState viewState = renderView.GetViewState();

                    if (viewState != null)
                    {
                        requestData.HasViewState = true;
                        requestData.ViewStateSolution = viewState.SolutionName;
                        requestData.ViewStateToken = Coolzon.ViewState.ViewState.ToToken(viewState);
                        requestData.ViewStateAge = viewState.Age;
                    }
                    else
                    {
                        requestData.HasViewState = false;
                    }
                }
                else
                {
                    requestData.HasViewState = false;
                }

                requestData.MainServerIP = UIContext.Current.MainServerIP;
                requestData.MainServerPort = UIContext.Current.MainServerPort;

                // 发送心跳信号，包括视图状态
                Request request = RequestUtil.BuildRequest(UIContext.Current.ControlDomainId,
                    UIContext.Current.UserIdentity,
                    SCENARIO.CONNECT,
                    COMMAND.CONNECT.UPLOADVIEWSTATE,
                    REQUEST_MODE.NORESPONSE,
                    requestData);

                //Common.Logger.DebugToTag(Library.LogTag, "Heartbeat thread service:发送心跳信号服务{0}:{1},state:{2},Client-State:{3}",
                //    proxy.IP,
                //    proxy.Port,
                //    proxy.State,
                //    proxy.Client.State);
                proxy.Client.SendRequest(request);

                netStateList.Add(new Coolzon.Event.UI.UINetConnectionStateFeedbackEvent.NetConnectionState(proxy.IP,
                    proxy.Port, true));
            }
            catch (Exception ex)
            {
                Common.Logger.ErrorToTag(Library.LogTag, "Heartbeat thread service:从服务{0}:{1}断开连接,state:{3},ex:{2}",
                    proxy.IP,
                    proxy.Port,
                    ex, proxy.State);

                proxy.GoToDisconnectState();

                if (errorProxyList == null)
                {
                    errorProxyList = new List<MainServiceProxy>();
                }
                errorProxyList.Add(proxy);

                netStateList.Add(new Coolzon.Event.UI.UINetConnectionStateFeedbackEvent.NetConnectionState(proxy.IP,
                    proxy.Port, false));
            }
        }
        private static void KeepAlive(ref List<MainServiceProxy> errorProxyList,
            List<Coolzon.Event.UI.UINetConnectionStateFeedbackEvent.NetConnectionState> netStateList,
            MainServiceProxy proxy)
        {
            if (proxy.State != ServiceProxyState.Connected)
            {
                if (proxy.State == ServiceProxyState.ReconnectFinished)
                {
                    Common.Logger.WarningToTag(Library.LogTag, "服务代理{0}:{1}的state:{2},修改为Connected,本次不发送心跳信号",
                        proxy.IP,
                        proxy.Port,
                        proxy.State);
                    proxy.State = ServiceProxyState.Connected;
                }

                netStateList.Add(new Coolzon.Event.UI.UINetConnectionStateFeedbackEvent.NetConnectionState(proxy.IP,
                    proxy.Port, false));
                return;
            }

            try
            {
                ReqUploadViewStateData requestData = new ReqUploadViewStateData();
                requestData.HasViewState = false;
                requestData.MainServerIP = UIContext.Current.MainServerIP;
                requestData.MainServerPort = UIContext.Current.MainServerPort;

                // 发送心跳信号，包括视图状态
                Request request = RequestUtil.BuildRequest(UIContext.Current.ControlDomainId,
                    UIContext.Current.UserIdentity,
                    SCENARIO.CONNECT,
                    COMMAND.CONNECT.UPLOADVIEWSTATE,
                    REQUEST_MODE.NORESPONSE,
                    requestData);

                proxy.Client.SendRequest(request);

                netStateList.Add(new Coolzon.Event.UI.UINetConnectionStateFeedbackEvent.NetConnectionState(proxy.IP,
                    proxy.Port, true));
            }
            catch (Exception ex)
            {
                Common.Logger.ErrorToTag(Library.LogTag, "Heartbeat thread service:从服务{0}:{1}断开连接,state:{3},ex:{2}",
                    proxy.IP,
                    proxy.Port,
                    ex, proxy.State);

                proxy.GoToDisconnectState();

                if (errorProxyList == null)
                {
                    errorProxyList = new List<MainServiceProxy>();
                }
                errorProxyList.Add(proxy);

                netStateList.Add(new Coolzon.Event.UI.UINetConnectionStateFeedbackEvent.NetConnectionState(proxy.IP,
                    proxy.Port, false));
            }
        }
    }
}